#pragma once

#include <iostream>
#include <math.h>

namespace Math{

    enum Error{ PARALLEL };

    struct Vector3{
        Vector3(){ x=y=z=0; }
        Vector3(float x, float y, float z): x(x), y(y), z(z){}

        float x;
        float y;
        float z;

        Vector3 operator+(Vector3& other);
        Vector3 operator-(Vector3& other);
    };

    typedef Vector3 Vertex;

    struct Vector4{
        Vector4(){ x=y=z=w=0; };
        Vector4(float x, float y, float z, float w):x(x), y(y), z(z), w(w){}
        Vector4(Vector3 v, float angle){ x=v.x; y=v.y; z=v.z; w=angle; }
        float x;
        float y;
        float z;
        float w;
    };

    struct Matrix3x3{
        float x1, x2, x3;
        float y1, y2, y3;
        float z1, z2, z3;
    };

    struct Matrix4x4{
        float x1, x2, x3, x4;
        float y1, y2, y3, y4;
        float z1, z2, z3, z4;
        float w1, w2, w3, w4;
    };

    void PrintMatrix3x3(Matrix3x3 m);
    void PrintVector(Vector3 v);
    void PrintVector(Vector4 v);

    Vector3 Vector4to3(Vector4 v);

    Vector3 i();
    Vector3 j();
    Vector3 k();

    Matrix3x3 Identity3x3();

    Matrix3x3 MatrixAddition3x3(Matrix3x3 a, Matrix3x3 b);

    Matrix3x3 MatrixScalarMultiplication3x3(Matrix3x3 m, float s);

    Matrix3x3 MatrixMultiplication3x3(Matrix3x3 a, Matrix3x3 b);

    Vector3 MatrixVectorMultiplication3f(Matrix3x3 m, Vector3 v);

    Vector4 MatrixVectorMultiplication4f(Matrix4x4 m, Vector4 v);

    Matrix3x3 SelfTensorProduct3f(Vector3 v);

    Vector3 ScalarProduct(Vector3 v, float s);

    Vector3 VectorAddition3f(Vector3 a, Vector3 b);

    float Magnitude(Vector3 v);

    Vector3 Normalise(Vector3 v);

    float DotProduct(Vector3 a, Vector3 b);

    float AngleBetween(Vector3 a, Vector3 b);

    bool ParallelVector(Vector3 a, Vector3 b);

    bool OpposedVector(Vector3 a, Vector3 b);

    Vector3 CrossProduct(Vector3 a, Vector3 b);

    Matrix3x3 VectorCrossProductMatrix3f(Vector3 v);

    Vector3 RotateVector(Vector3 v, Vector3 axis, float angle);
}
